package com.fadis.db;

import com.fadis.FadisException;
import com.fadis.data.FBloomFilter;
import com.fadis.data.FHyperLoglog;
import com.fadis.data.base.FadisString;
import com.fadis.data.base.StringList;
import com.fadis.data.base.StringSet;
import com.fadis.data.base.StringZSet;
import com.fadis.data.bloomfilter.BloomFilter;
import com.fadis.data.hyperloglog.HyperLogLog;
import com.fadis.expire.ExpireInfo;
import com.fadis.expire.ExpireMgmr;
import com.fadis.watch.FadisWatcher;

import java.util.HashMap;
import java.util.Map;

public class FadisDB {

    private static Map<String, Object> repo = new HashMap<>();
    public static Map<String, ExpireInfo> expireTime = new HashMap<>();

//    public static Map<String, Object> data(){
//        return repo;
//    }

    public static void remove(String key){
        if(repo.containsKey(key)){
            repo.remove(key);
            FadisWatcher.onKeyDeleted(key);
        }
    }

    public static void put(String key, Object o){
        boolean contains = repo.containsKey(key);
        repo.put(key, o);
        if(!contains){
            FadisWatcher.onKeyCreated(key);
        }else{
            FadisWatcher.onKeyUpdated(key);
        }
    }

    public static void clear(){
        repo.clear();
        FadisDB.expireTime.clear();
    }

    public static boolean containsKey(String key){
        ExpireMgmr.checkAndDelete(key);
        return repo.containsKey(key);
    }

    public static Object get(String key){
        ExpireMgmr.checkAndDelete(key);
        return repo.get(key);
    }

    public static Double tryToGetOrCreateDouble(String key, boolean createIfNotExists){
        if(FadisDB.containsKey(key)){
            if(!(FadisDB.get(key) instanceof FadisString)){
                throw new FadisException(4001, "WRONGTYPE Operation against a key holding the wrong kind of value");
            }
            try {
                Double v = Double.parseDouble(((FadisString) FadisDB.get(key)).getStr());
                return v;
            }catch (Exception e){
                throw new FadisException(4001, "(error) ERR Operation against a key holding the wrong kind of value, not long: " + key);
            }
        }else if(createIfNotExists){
            FadisString s = new FadisString("0");
            FadisDB.put(key, s);
            return 0.0;
        }else{
            return null;
        }
    }

    public static Long tryToGetOrCreateLong(String key, boolean createIfNotExists){
        if(FadisDB.containsKey(key)){
            if(!(FadisDB.get(key) instanceof FadisString)){
                throw new FadisException(4001, "WRONGTYPE Operation against a key holding the wrong kind of value");
            }
            try {
                Long v = Long.parseLong(((FadisString) FadisDB.get(key)).getStr());
                return v;
            }catch (Exception e){
                throw new FadisException(4001, "(error) ERR Operation against a key holding the wrong kind of value, not long: " + key + "==>" + FadisDB.get(key));
            }
        }else if(createIfNotExists){
            FadisString s = new FadisString("0");
            FadisDB.put(key, s);
            return 0L;
        }else{
            return null;
        }
    }

    public static FadisString tryToGetOrCreateString(String key, boolean createIfNotExists){
        if(FadisDB.containsKey(key)){
            if(!(FadisDB.get(key) instanceof FadisString)){
                throw new FadisException(4001, "WRONGTYPE Operation against a key holding the wrong kind of value");
            }
            return (FadisString) FadisDB.get(key);
        }else if(createIfNotExists){
            FadisString s = new FadisString("");
            FadisDB.put(key, s);

            return s;
        }else{
            return null;
        }
    }

    public static StringList tryToGetOrCreateList(String key, boolean createIfNotExists){

        if(FadisDB.containsKey(key)){
            if(!(FadisDB.get(key) instanceof StringList)){
                throw new FadisException(4001, "WRONGTYPE Operation against a key holding the wrong kind of value");
            }
            return (StringList) FadisDB.get(key);
        }else if(createIfNotExists){
            StringList list = new StringList();
            FadisDB.put(key, list);
            return list;
        }else{
            return null;
        }
    }

    public static StringSet tryToGetOrCreateSet(String key, boolean createIfNotExists){

        FadisWatcher.beforeVisitKey(key);
        if(FadisDB.containsKey(key)){
            if(!(FadisDB.get(key) instanceof StringSet)){
                throw new FadisException(4001, "WRONGTYPE Operation against a key holding the wrong kind of value");
            }
            return (StringSet) FadisDB.get(key);
        }else if(createIfNotExists){
            StringSet list = new StringSet();
            FadisDB.put(key, list);

            return list;
        }else{
            return null;
        }
    }

    public static StringZSet tryToGetOrCreateZSet(String key, boolean createIfNotExists){

        if(FadisDB.containsKey(key)){
            if(!(FadisDB.get(key) instanceof StringZSet)){
                throw new FadisException(4001, "WRONGTYPE Operation against a key holding the wrong kind of value");
            }
            return (StringZSet) FadisDB.get(key);
        }else if(createIfNotExists){
            StringZSet list = new StringZSet();
            FadisDB.put(key, list);

            return list;
        }else{
            return null;
        }
    }

    public static HyperLogLog tryToGetOrCreateHyperLogLog(String key, boolean createIfNotExists){

        if(FadisDB.containsKey(key)){
            if(!(FadisDB.get(key) instanceof HyperLogLog)){
                throw new FadisException(4001, "WRONGTYPE Operation against a key holding the wrong kind of value");
            }
            return (HyperLogLog) FadisDB.get(key);
        }else if(createIfNotExists){
            HyperLogLog list = FHyperLoglog.create();
            FadisDB.put(key, list);
            return list;
        }else{
            return null;
        }
    }

    public static HashMap<String, String> tryToGetOrCreateHash(String key, boolean createIfNotExists){

        if(FadisDB.containsKey(key)){
            if(!(FadisDB.get(key) instanceof HashMap)){
                throw new FadisException(4001, "WRONGTYPE Operation against a key holding the wrong kind of value");
            }
            return (HashMap<String, String>) FadisDB.get(key);
        }else if(createIfNotExists){
            HashMap<String, String> list = new HashMap<>();
            FadisDB.put(key, list);

            return list;
        }else{
            return null;
        }
    }

    public static BloomFilter tryToGetOrCreateBloomFilter(String key, boolean createIfNotExists){

        if(FadisDB.containsKey(key)){
            if(!(FadisDB.get(key) instanceof BloomFilter)){
                throw new FadisException(4001, "WRONGTYPE Operation against a key holding the wrong kind of value");
            }
            return (BloomFilter) FadisDB.get(key);
        }else if(createIfNotExists){
            BloomFilter list = FBloomFilter.create();
            FadisDB.put(key, list);

            return list;
        }else{
            return null;
        }
    }



    public static boolean isDouble(String key){
        if(FadisDB.containsKey(key)){
            if(!(FadisDB.get(key) instanceof FadisString)){
                throw new FadisException(4001, "WRONGTYPE Operation against a key holding the wrong kind of value");
            }
            try {
                Double v = Double.parseDouble(((FadisString) FadisDB.get(key)).getStr());
                return true;
            }catch (Exception e){
                return false;
            }
        }
        return false;
    }

    public static boolean isLong(String key){
        if(FadisDB.containsKey(key)){
            if(!(FadisDB.get(key) instanceof FadisString)){
                throw new FadisException(4001, "WRONGTYPE Operation against a key holding the wrong kind of value");
            }
            try {
                Long v = Long.parseLong(((FadisString) FadisDB.get(key)).getStr());
                return true;
            }catch (Exception e){
                return false;
            }
        }
        return false;
    }

    public static boolean isString(String key){
        if(FadisDB.containsKey(key)){
            if(!(FadisDB.get(key) instanceof FadisString)){
                return false;
            }
            return true;
        }
        return false;
    }
}
